package com.blog.aspect;

import com.blog.annotation.RequiredLog;
import com.blog.entity.Log;
import com.blog.entity.User;
import com.blog.mapper.LogMapper;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Date;

@Aspect
@Component
public class LogAspect {

    private static final Logger log= LoggerFactory.getLogger(LogAspect.class);

    @Pointcut("@annotation(com.blog.annotation.RequiredLog)")
    public void doLog(){}

    @Around("doLog()")
    public Object doLogAround(ProceedingJoinPoint joinPoint)throws Throwable{
        int status=1;
        String error="";
        long time=-1;
        long t1=System.currentTimeMillis();
        try {
            Object result = joinPoint.proceed();
            long t2 = System.currentTimeMillis();
            time = t2 - t1;
            return result;
        }catch (Throwable e){
            e.printStackTrace();
            long t3=System.currentTimeMillis();
            time=t3-t1;
            status=0;
            error=e.getMessage();
            throw e;
        }finally{
            saveUserLog(joinPoint,time,status,error);
        }
    }

    @Autowired
    private LogMapper logMapper;
    private void saveUserLog(ProceedingJoinPoint joinPoint,long time,int status,String error) throws NoSuchMethodException, JsonProcessingException {
        //1.获取用户行为日志
        ServletRequestAttributes requestAttributes=
                (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = requestAttributes.getRequest();
        String ip=request.getRemoteAddr();
        User user=(User)request.getSession().getAttribute("user");
        String username="user";
        if(user!=null) username=user.getUsername();
        Class<?> targetCls = joinPoint.getTarget().getClass();
        MethodSignature ms = (MethodSignature) joinPoint.getSignature();
        Method targetMethod = targetCls.getDeclaredMethod(ms.getName(), ms.getParameterTypes());
        RequiredLog requiredLog = targetMethod.getAnnotation(RequiredLog.class);
        String operation= requiredLog.operation();
        String method=targetCls.getName()+"."+targetMethod.getName();
        String params=new ObjectMapper().writeValueAsString(joinPoint.getArgs());
        //2.封装用户行为日志
        Log userLog=new Log();
        userLog.setIp(ip);
        userLog.setUsername(username);
        userLog.setOperation(operation);
        userLog.setCreatedTime(new Date());
        userLog.setMethod(method);
        userLog.setParams(params);
        userLog.setTime(time);
        userLog.setStatus(status);
        userLog.setError(error);
        //3.输出并存储用户行为日志
        log.info("user log is {}",userLog);
        logMapper.insert(userLog);
    }
}